package org.jeecg.modules.meter.controller;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.SsoUtil;
import org.jeecg.common.util.StringUtils;
import org.jeecg.common.util.sms.SmsUtil;
import org.jeecg.entity.charge.ChargeStandard;
import org.jeecg.entity.meter.*;
import org.jeecg.enums.PayStatusEnum;
import org.jeecg.enums.SmsBusinessTypeEnum;
import org.jeecg.enums.car.CarSyncStatusEnum;
import org.jeecg.enums.meter.*;
import org.jeecg.model.charge.reqvo.DayReportReqVo;
import org.jeecg.model.charge.resvo.DayReportRespVo;
import org.jeecg.model.meter.resvo.MeterUseListRespVo;
import org.jeecg.modules.message.entity.SysMessage;
import org.jeecg.modules.meter.iot.entity.MeterCollectInfoDto;
import org.jeecg.modules.meter.service.*;
import org.jeecg.modules.system.entity.SmsEntity;
import org.jeecg.modules.system.entity.SysSms;
import org.jeecg.modules.system.service.ISysSmsService;
import org.jeecg.vo.meter.MeterChargeRespVo;
import org.jeecg.vo.meter.MeterCollectReqVo;
import org.jeecg.vo.meter.MeterSmsRespVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DateTime.now;

@RestController
@RequestMapping("/api/meter")
@Slf4j
public class  MeterDataApiController {
    @Autowired
    private IMeterUseService meterUseService;
    @Autowired
    private IMeterChargeInfoService meterChargeInfoService;
    @Autowired
    private IMeterFeeRuleService meterFeeRuleService;
    @Autowired
    private IMeterService meterService;
    @Autowired
    private IMeterGatewayService meterGatewayService;
    @Autowired
    private MeterIotService meterIotService;
    @Autowired
    private IMeterReadService meterReadService;
    @Autowired
    private IMeterOrderService meterOrderService;
    @Autowired
    private ISysSmsService messageService;
    @Autowired
    private IMeterAccountService meterAccountService;

    private static String  templateCode ="SMS_208625383";
    @Autowired
    private IMeterControlSwitchService meterControlSwitchService;

    @Autowired
    @Lazy
    private IMeterHandReadService meterHandReadService;




    @GetMapping(value = "/meterList")
    public Result<Page<Meter>> meterList(HttpServletRequest request, @RequestParam(name = "roomId") String roomId,@RequestParam(name = "tenantIds") String tenantIds,
                                         @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                         @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize
    ) {

        Result<Page<Meter>> result = new Result<Page<Meter>>();
        try {
            Page<Meter> page = new Page<Meter>(pageNo, pageSize);
            Meter meter = new Meter();
            meter.setRoomName(roomId);
            meter.setTenantId(tenantIds);
            List<Meter> list = meterService.findPage(page,meter);
            page.setRecords(list);
            result.setSuccess(true);
            result.setResult(page);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }
    @ApiOperation(value="设备模块日收款汇总报表-列表查询", notes="设备模块日收款汇总报表-列表查询")
    @PostMapping(value = "/meterFindGroupList")
    public List<DayReportRespVo> findGroupList (@RequestBody DayReportReqVo dayReportReqVo){
          return meterOrderService.apiFindGroupList(dayReportReqVo);
    }

    @PostMapping(value = "/refreshMeterRead")
    public Result<?> refreshMeterRead() {
        StringBuilder resMsg = new StringBuilder();
        List<Meter> totalMeterList = meterService.findMeterList();
        int totalSize = totalMeterList.size();
        int toIndex = 100 ;
        int successMeter = 0;
        for (int i=0;i<totalSize;i+=100){
            if (i+100 > totalSize){
                toIndex = totalSize - i;
            }
            List<Meter> meterList = totalMeterList.subList(i, i + toIndex);
            HashMap<String, MeterCollectReqVo> gatewayMap = new HashMap<>();
            for (Meter meter : meterList) {
                //只有状态为正常的仪表才可读数读数
                if (meter.getUseStatus() != MeterStatusEnum.USE_NORMAL.getCode()) {
                    resMsg.append(meter.getMeterCode()).append("状态为");
                    resMsg.append(MeterUseStatusEnum.getDesc(meter.getUseStatus())).append("不可读表;");
                    continue;
                }
                if (meter.getSyncStatus() != CarSyncStatusEnum.SYNC_STATUS_YES.getCode()){
                    resMsg.append(meter.getMeterCode()).append("非同步状态,读表失败;");
                    continue;
                }
                if (StringUtils.isBlank(meter.getMeterKey())){
                    resMsg.append(meter.getMeterCode()).append("仪表key不存在,请同步仪表,读表失败;");
                    continue;
                }
                //获取仪表对应的收费项单价 获取有效期收费项单价
                MeterFeeRule meterFeeRule = meterFeeRuleService.queryFeeByMeterId(meter.getId());
                if (meterFeeRule == null || meterFeeRule.getFeePrice() == null ) {
                    resMsg.append(meter.getMeterCode()).append("没有配置收费项或已过有效期;");
                    continue;
                }
                BigDecimal price = meterFeeRule.getFeePrice();
                Integer precision = meterFeeRule.getFeePrecision();
                Integer roundMode = meterFeeRule.getRoundMode();
                MeterCollectReqVo meterCollectReqVo = gatewayMap.get(meter.getMeterGateway());
                if (meterCollectReqVo == null) {
                    meterCollectReqVo = new MeterCollectReqVo();
                    MeterGateway meterGateway = meterGatewayService.queryById(meter.getMeterGateway());
                    if (meterGateway != null) BeanUtils.copyProperties(meterGateway,meterCollectReqVo);
                    //存储同一网关单个仪表
                    gatewayMap.put(meter.getMeterGateway(), meterCollectReqVo);
                }
                meterCollectReqVo.getMeterIdList().add(meter.getId());
                meterCollectReqVo.getMeterKeyList().add(meter.getMeterKey());
                meter.setLoss(meter.getLoss());//线损
                meter.setPrice(price);//单价
                meter.setPrecision(precision); //计费精度
                meter.setRoundModal(roundMode);
                meterCollectReqVo.getMeterMap().put(meter.getMeterKey(), meter);
            }
            ArrayList<MeterChargeInfo> meterChangeInfos = new ArrayList<>();
            //存储读数
            for (Map.Entry<String, MeterCollectReqVo> mcrq : gatewayMap.entrySet()) {
                try{
                    MeterCollectReqVo value = mcrq.getValue();
                    if (value.getMeterKeyList().size() > 0) {
                        List<MeterRead> nowMeterReadList = new ArrayList<MeterRead>();
                        List<MeterCollectInfoDto> collectNowList = meterIotService.getCollectInfo(StringUtils.join(value.getMeterKeyList(), ","),null,value.getRequestUrl() , value.getIotType());
                        if (collectNowList == null || collectNowList.size() <= 0){
                            resMsg.append(StringUtils.join(value.getMeterKeyList())).append("读表失败");
                            continue;
                        }
                        //获取最新的一条 水电表 读数信息   负数的情况
                        List<MeterRead> preMeterReadList = meterReadService.findLastMeterReads(value.getMeterIdList());
                        Map<String, MeterRead> preMeterReadMap = new HashMap<String, MeterRead>();
                        for (MeterRead preRead : preMeterReadList) {
                            preMeterReadMap.put(preRead.getMeterKey(), preRead);
                        }
//                        List<Meter> onlyReadTimeList = new ArrayList<>();  //读数为0的表,只更新读表时间
                        for (MeterCollectInfoDto meterRead : collectNowList) {
                            MeterRead nowRead = new MeterRead();
                            MeterRead preRead = preMeterReadMap.get(meterRead.getMeterKey());
                            Meter priceInfo = value.getMeterMap().get(meterRead.getMeterKey());
                            if (priceInfo == null) {//没有配置单价线损，信息有误
                                continue;
                            }
                            //本次最新读数
                            BigDecimal compareTotalUse = BigDecimal.ZERO;
                            BigDecimal nowTotalUse = meterRead.getTotalUse() == null? BigDecimal.ZERO:new BigDecimal(meterRead.getTotalUse());
                            compareTotalUse = nowTotalUse.setScale(0,BigDecimal.ROUND_DOWN); //向下取整
                            if(compareTotalUse.compareTo(BigDecimal.ZERO) < 0){ //读数小于0 忽略
                                continue;
                            }
                            BigDecimal bigRate = new BigDecimal(priceInfo.getRate());
                            if (preRead == null){
                                nowRead.setId(String.valueOf(IdWorker.getId()));
                                nowRead.setTenantId(priceInfo.getTenantId());
                                nowRead.setMeterId(priceInfo.getId());
                                nowRead.setPrice(priceInfo.getPrice().toString());
                                nowRead.setPrecision(priceInfo.getPrecision());
                                nowRead.setLoss(priceInfo.getLoss().toString());
                                nowRead.setRate(priceInfo.getRate());
                                nowRead.setReadTime(DateUtils.str2Date(meterRead.getReadTime(),DateUtils.datetimeFormat));
                                BigDecimal preTotalUse = priceInfo.getBeginUse() == null ? BigDecimal.ZERO: new BigDecimal(priceInfo.getBeginUse());
                                nowRead.setPreRead(preTotalUse.toString());
                                nowRead.setNowRead(nowTotalUse.toString());
                                nowRead.setNowUse((nowTotalUse.subtract(preTotalUse)).multiply(bigRate).toString());
                                nowRead.setCloseStatus(MeterDeductStatusEnum.METER_DEDUCT_STATUS_OK.getCode());
                                nowRead.setIsBegin(MeterBeginStatusEnum.METER_DEDUCT_BEGIN_YES.getCode());
                                nowMeterReadList.add(nowRead);
                            }else {
                                BigDecimal preTotalUse = preRead.getNowRead() == null ? BigDecimal.ZERO: new BigDecimal(preRead.getNowRead());
                                BigDecimal compareToPreTotalUse = nowTotalUse.setScale(0,BigDecimal.ROUND_DOWN);
                                if (compareTotalUse.compareTo(compareToPreTotalUse) >= 0 ){
                                    nowRead.setId(String.valueOf(IdWorker.getId()));
                                    nowRead.setTenantId(priceInfo.getTenantId());
                                    nowRead.setMeterId(preRead.getMeterId());
                                    nowRead.setCloseStatus(MeterDeductStatusEnum.METER_DEDUCT_STATUS_OK.getCode());
                                    nowRead.setPreRead(preRead.getNowRead());
                                    nowRead.setNowRead(nowTotalUse.toString());
                                    nowRead.setNowUse((nowTotalUse.subtract(preTotalUse)).multiply(bigRate).toString());
                                    nowRead.setLoss(priceInfo.getLoss().toString());
                                    nowRead.setRate(priceInfo.getRate());
                                    nowRead.setPrice(priceInfo.getPrice().toString());
                                    nowRead.setPrecision(priceInfo.getPrecision());
                                    nowRead.setReadTime(DateUtils.str2Date(meterRead.getReadTime(),DateUtils.datetimeFormat));
                                    nowRead.setIsBegin(MeterBeginStatusEnum.METER_DEDUCT_BEGIN_NOT.getCode());
                                    nowMeterReadList.add(nowRead);
                                } /*else {
                                    //未变化 当前总读数 = 历史总读数
                                    resMsg.append(preRead.getMeterKey()).append("读数无变化</br>");
                                    continue;
                                }*/
                            }
                            //构造扣费明细
                            if (null != nowRead && StringUtils.isNotBlank(nowRead.getNowUse()) && new BigDecimal(nowRead.getNowUse()).compareTo(BigDecimal.ZERO) >= 0 ){
                                BigDecimal price = StringUtils.isEmpty(nowRead.getPrice()) ? BigDecimal.ZERO: new BigDecimal(nowRead.getPrice());
                                BigDecimal loss =  StringUtils.isEmpty(nowRead.getLoss())? BigDecimal.ONE: new BigDecimal(nowRead.getLoss());
//                                BigDecimal rate = nowRead.getRate() == null ? BigDecimal.ONE: new BigDecimal(nowRead.getRate());
                                BigDecimal nowUse = StringUtils.isEmpty(nowRead.getNowUse()) ? BigDecimal.ZERO: new BigDecimal(nowRead.getNowUse());
                                BigDecimal amount = nowUse.multiply(price);
                                amount = BigDecimal.ZERO.subtract(amount);
                                MeterChargeInfo meterCharge = new MeterChargeInfo();
                                meterCharge.setChargeUse(nowUse.toString());
                                meterCharge.setTenantId(priceInfo.getTenantId());
                                meterCharge.setChargeAmount(amount.setScale(nowRead.getPrecision(),priceInfo.getRoundModal()).toString());
                                meterCharge.setPrecision(nowRead.getPrecision());
                                meterCharge.setChargeType(MeterChargeTypeEnum.METER_CHARGE_TYPE_DOCK.getCode());
                                meterCharge.setChargeTime(new Date());
                                meterCharge.setMeterId(priceInfo.getId());
                                meterCharge.setChargeStatus(MeterChargeStatusEnum.METER_CHARGE_STATUS_OK.getCode());
                                meterCharge.setTotalUse(nowRead.getNowRead());
                                meterCharge.setReadTime(nowRead.getReadTime());
                                meterCharge.setProjectId(priceInfo.getProjectId());
                                meterCharge.setPaymentStatus(PayStatusEnum.PAY_STATUS_YES.getCode());
                                meterCharge.setRound(priceInfo.getRoundModal());
                                meterCharge.setMeterReadId(nowRead.getId());
                                meterChangeInfos.add(meterCharge);
                            }
                        }
                        if (nowMeterReadList.size() >0 ){
                            meterReadService.saveBatch(nowMeterReadList);
                        }
                        /*if (onlyReadTimeList.size() > 0 ){
                            meterAccountService.refreshReadTimeBatch(onlyReadTimeList);
                        }*/
                        List<MeterChargeRespVo> meterChargeRespVoList = new ArrayList<>();
                        if (meterChangeInfos.size() > 0 ){
                            meterChargeInfoService.saveBatch(meterChangeInfos);
                            meterChangeInfos.forEach(temp->{
                                MeterChargeRespVo meterChargeRespVo = new MeterChargeRespVo();
                                BeanUtils.copyProperties(temp,meterChargeRespVo);
                                meterChargeRespVoList.add(meterChargeRespVo);
                            });
                            meterChargeInfoService.refreshRemainByPay(meterChargeRespVoList,"自动读表",MeterChargeTypeEnum.METER_CHARGE_TYPE_DOCK.getCode());
                        }
                    }
                }catch (Exception e){
                    throw new RuntimeException("读取仪表设备异常",e);
                }
                successMeter += meterChangeInfos.size();
            }

        }
        if (resMsg.length() > 0){
            if (successMeter > 0 ){
                resMsg.append("以外的表读取成功");
            }
            return Result.error(resMsg.toString());
        }
        if (successMeter == 0 ){
            return Result.error("读表无变化");
        }
        return Result.ok("操作成功");

    }
   @RequestMapping("sendMeterWaringSms")
    public Result<?> sendMeterWaringSms() {
        String phone = "";
        //统计需要发送短信的表
        List<MeterSmsRespVo> meterSmsRespVoList = meterService.queryMeterSms();
        ArrayList<SysSms> sysSmsList = Lists.newArrayList();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //表有多个房间--》多个业主认证
        for (MeterSmsRespVo meterSmsRespVo : meterSmsRespVoList) {
             if (StringUtils.isEmpty(meterSmsRespVo.getApplyTel())){
                if (StringUtils.isEmpty(meterSmsRespVo.getPhone())){
                    continue;
                }else {
                    phone = meterSmsRespVo.getPhone();
                }
             }else {
                 phone = meterSmsRespVo.getApplyTel();
             }
             //取最新发送短信
            SysMessage sysMessage = meterService.querySmsIsSend(meterSmsRespVo.getId());
            if (sysMessage == null || sysMessage.getSmsLevel()==0){
               SmsEntity smsEntity = SmsUtil.sendSms(phone, templateCode, "date", sdf.format(meterSmsRespVo.getReadTime()).toString(), "balance", meterSmsRespVo.getRemainAmount());
                //短信
                SysSms sms = new SysSms();
                if (smsEntity.getMessage().equalsIgnoreCase("OK")){
                    sms.setEsSendStatus("1");
                }else {
                    sms.setEsSendStatus("2");
                }
                sms.setId(String.valueOf(IdWorker.getId()));
                sms.setTenantId(String.valueOf(meterSmsRespVo.getTenantId()));
                sms.setProjectId(meterSmsRespVo.getProjectId());
                sms.setBusinessType(SmsBusinessTypeEnum.SMS_METER.getCode());
                sms.setBusinessId(meterSmsRespVo.getId());
                sms.setEsTitle(SmsBusinessTypeEnum.SMS_METER.getDesc());
                sms.setEsType(1);
                sms.setEsReceiver(phone);
                sms.setEsContent(smsEntity.getContent());
                sms.setEsBizId(smsEntity.getBizId());
                sms.setSmsLevel(1);
                sms.setCreateTime(now());
                sms.setEsSendTime(now());
                messageService.addMessage(sms);
            }
        }
        return  Result.ok("短信发送成功");
    }


    @ApiOperation(value="更新手抄表账单生成状态", notes="更新手抄表账单生成状态")
    @PostMapping(value = "/hand/rollBackBillsStatus")
    public Integer rollBackBillsStatus (String handId){
         return meterHandReadService.rollBackBillsStatus(handId);
    }
    /**
     * 定时查询日用量
     */
    @RequestMapping("meterDayUse")

    public Result<?> meterDayUse(){
        List<MeterUseListRespVo> meterUseListRespVos = meterService.queryUseList();
         Integer count = meterService.queryMeterUseCount();
        //第一次执行定时器
        if ( count == 0){
            meterUseService.saveBatch(meterUseListRespVos);
            return null;
        }else {
            List<MeterUseListRespVo> meterMonthUse = meterService.getMeterMonthUse();
            //更新使用量
            meterService.updateMonthMeterUse(meterUseListRespVos);
            //过滤出新增的
            for (MeterUseListRespVo map : meterMonthUse) {
                meterUseListRespVos = meterUseListRespVos.stream().filter(x->!(map.getMonth().equals(x.getMonth())&&map.getMeterCode().equals(x.getMeterCode()) )).collect(Collectors.toList());
            }
            if ( meterUseListRespVos .size() >0){
                //存入新产生的月份数据
                meterUseService.saveBatch(meterUseListRespVos);
            }
        }
        return null;
    }
}
